module datapath(
	iClk, iPCreset,
	iInstAddr,	// iInstWrite == 1의 상태에서 접근되는 instruction 주소 [7:0]
	iControl,	// control 신호. control unit의 출력 [10:0]
	oOPcode,		// instruction의 상위 6-bit [31:26]
	oFuncCode,	// instruction의 하위 6-bit [5:0]
	oDataMemOut	// dataMemory read시의 출력
	);
	
	input iClk, iPCreset;
	input [7:0] iInstAddr;
	input [10:0] iControl;
	output [5:0] oOPcode, oFuncCode;
	output [7:0] oDataMemOut;
	
	reg [31:0] regPC;	// PC counter







//======This Wires are Added For Multy Cycle=============//
	wire [7:0] regALUout, regA, regB;
	wire [4:0] RF_WriteReg;
	wire [7:0] wMemAddr;
	wire [7:0] wDataMemOut;
	wire [31:0] wSE_Inst, wSE_Shift_inst;
//=======================================================//







	/* 변수명의 cw는 control wire를 의미한다. */
	wire [2:0] cwALUop;
	wire cwRegDst, cwRegWrite, cwALUsrc,
		  cwMemWrite, cwMemRead, cwMemtoReg,
		  /*cwPCsrc, cwExtOp,: 불필요 */ cwBranch, cwJump;
	wire [31:0] wInst;	// instruction
	wire [4:0] wRegFileWriteAdr;
	wire [7:0] wInstAddr,
				  wRegFileRead1, wRegFileRead2, wRegFileWriteDat,	// register_file
				  wALU_iB, wALUresult;
	wire [1:0] wALUflag; // ALU_8

	assign oOPcode = wInst[31:26];
	assign oFuncCode = wInst[5:0];
	
	/* iControl을 명시적으로 표현 */
	assign cwRegDst = iControl[10];
	assign cwRegWrite = iControl[9];
	assign cwALUsrc = iControl[8];
	assign cwALUop = iControl[7:5];
	assign cwMemWrite = iControl[4];
	assign cwMemRead = iControl[3];
	assign cwMemtoReg = iControl[2];
	/* assign cwPCsrc = iControl"3"; :불필요 */
	/* assign cwExtOp = iControl"2"; :불필요. sign extend를 하기에는 PC 값이 작음 */
	assign cwBranch = iControl[1];
	assign cwJump = iControl[0];
	
	/* register file 관련 */
	assign wRegFileWriteAdr = (cwRegDst)? wInst[15:11]:wInst[20:16];
	assign wRegFileWriteDat = (cwMemtoReg)? oDataMemOut:wALUresult;
	
	/* Program Counter 관련 */
	wire [31:0] wPCadd4, wPCbran, wPCjump;	// PC+4/ BRANCH/ JUMP
	
	/* ALU의 iB를 레지스터 값으로 할 것인지 immediate 값으로 할 것인지 선택.
		원래 immediate는 16-bit이지만 하위 8-bit만 사용했음.*/
	assign wALU_iB = (cwALUsrc)? wInst[7:0]:wRegFileRead2; 
	
/*M*/	 
/*lord*/assign wMemAddr = (conlorD)? ALUOut:regPC[7:0];
	dataMemory datMem(
		iClk,
		conMemWrite,			// 1일 때 write 한다.
		conMemRead,			// 1일 때 read 한다.
		wMemAddr,			// 접근 주소
		regBout,	// write시 사용할 Data
		oDataMemOut		// read시의 출력
		);


	Register Mem2RegF(iClk, oDataMemOut, wDataMemOut);
	instMemory instMem(
		iClk,
		conMemRead,
		conMemWrite,
		wInstAddr,	// PC-counter의 출력. Instruction의 주소(4의 배수)
		regBout, //iInstInput
		wInst		// target instruction
	);
	
	//MUX Ins2Reg
	assign RF_WriteReg = (conRegDst) ? wInst[15:11] : wInst[20:16];
	assign RF_WriteData = (conMemtoReg) ? wDataMemOut[7:0] : regALUOut[7:0];

	register_file regFile(
		iClk,
		conIRwrite,			// Enable write at ENB == 1
		wInst[25:21],		// Register address to Read 1
		wInst[20:16],		// Register address to Read 2
		RF_WriteReg,	// Register address to Write
		RF_WriteData,	// Data to Write
		wRegFileRead1,		// Data getting out
		wRegFileRead2		// Data getting out
		);
	Register A(iClk, wRegFileRead1, regA);
	Register B(iClk, wRegFileRead2, regB);
	SignExtend16to32(wInst[15:0], wSE_inst[31:0])
	ShifterLeft2bit(wSE_inst[31:0], wSE_Shift_inst[31:0]);

//Mux RF 2 ALU
	assign wALUin1 = (conALUSrcA) ? regA[7:0], regPC[7:0];
	assign wALUin2 = (conALUSrcB==0) ? regB[7:0] : ( (conALUSrcB==1) ? 8'b4 : ( (conALUSrcB==2) ? wSE_inst[31:0] : ( (conALUSrcB==3) wSE_Shift_inst[31:0] ) ) ) );


	ALU_8 ALU(
		cwALUop,			// ALUop [2:0]
		wRegFileRead1,	// input [7:0]
		wALU_iB,			// input [7:0]
		wALUresult,		// Arithmetic Result [7:0]
		oCarry,			// highest Carry
		wALUflag			// [1]=zero, [0]=Overflow
		);
	
	assign wPCadd4 = regPC + 32'd4;
	assign wPCbran = wPCadd4 + {(wInst[15] == 1)? -14'd1:14'd0, wInst[15:0], 2'd0};
	assign wPCjump = {wPCadd4[31:28], wInst[25:0], 2'd0};

	always @(posedge iClk)
		begin
			if(iPCreset)
				begin
					regPC <= 32'd0;
				end
			else
				begin
					regPC <= (iInstWrENB)?regPC:( (cwJump)? wPCjump: ( (cwBranch & wALUflag[1])? wPCbran:wPCadd4 ) );
				end
		end
	
endmodule
